package com.snake.excel2java.excel.blindbox;

import com.snake.excel2java.excel.common.ext.file.GroupExt;
import com.snake.excel2java.excel.common.ext.row.GroupRowExt;
import com.snake.excel2java.excel.global.ext.GlobalExt;
import com.snake.excel2java.excel.type.DropType;
import com.snake.excel2java.excel.type.ShoprankType;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.LinkedList;
import java.util.List;
import java.util.Random;

@Slf4j
@Component
public class OpenBlindBox {

    public static final Random RANDOM = new Random();
    public static final Random INDEX_RANDOM = new Random();
    public static final Random HIT_RANDOM = new Random();

    @Autowired
    GroupExt groupExt;

    @Autowired
    GlobalExt globalExt;

    public List<Integer> convertGroupToShopItem(List<GroupRowExt> groupList) {

        List<Integer> dropItemList = new LinkedList<>();
        for(GroupRowExt row: groupList) {
            dropItemList.add(row.getShopId());
        }

        return dropItemList;
    }


//    public synchronized List<GroupRowExt> open(long uid, OpenType type, int groupId, Set<Integer> execludeShopIdSet) {
    public synchronized List<GroupRowExt>  drop(long uid, DropType type, int groupId) {

        List<GroupRowExt> useGroupRowList = groupExt.getListByGroupId(groupId);

        int totalWeight = 0;
        for(GroupRowExt groupRow: useGroupRowList) {
            totalWeight += groupRow.getWeight();
        }

        List<GroupRowExt> dropGroupList = null;
        return  switch (type) {
            case one -> dropOne(uid, totalWeight, useGroupRowList);
            case three -> dropThree(uid, globalExt.getGlobalData().getDropThree(), totalWeight, useGroupRowList);
            case ten -> dropTen(uid, globalExt.getGlobalData().getDropTen(), groupId, totalWeight, useGroupRowList);
            default -> null;
        };


    }

    public synchronized List<GroupRowExt>  dropTest(long uid, DropType type, int groupId) {

        List<GroupRowExt> useGroupRowList = groupExt.getListByGroupId(groupId);

        int totalWeight = 0;
        for(GroupRowExt groupRow: useGroupRowList) {
            totalWeight += groupRow.getWeight();
        }

        return switch (type) {
            case one -> dropOne(uid, totalWeight, useGroupRowList);
            case three -> dropThree(uid, globalExt.getGlobalData().getDropThree(), totalWeight, useGroupRowList);
            case ten -> dropTen(uid, globalExt.getGlobalData().getDropTen(), groupId, totalWeight, useGroupRowList);
            default -> null;
        };

    }


    private List<GroupRowExt> dropOne(long uid, int totalWeight, List<GroupRowExt> useGroupRowList) {

        List<GroupRowExt> list = new LinkedList<>();
        GroupRowExt row = drop(totalWeight, useGroupRowList, RANDOM);
        list.add(row);
//        log.info("uid: {} dropOne groupId: {} shopId: {} rank: {}", uid, row.getGroupId(), row.getShopId(), row.getRank());

        return list;
    }

    private List<GroupRowExt> dropThree(long uid, int count, int totalWeight, List<GroupRowExt> useGroupRowList) {

        List<GroupRowExt> list = new LinkedList<>();
        for(int i = 0; i < count; ++i) {

            GroupRowExt row = drop(totalWeight, useGroupRowList, RANDOM);
            list.add(row);
//            log.info("uid: {} dropThree groupId: {} shopId: {} rank: {}", uid, row.getGroupId(), row.getShopId(), row.getRank());
        }

        return list;
    }

    private List<GroupRowExt> dropTen(long uid, int count, int groupId, int totalWeight, List<GroupRowExt> useGroupRowList) {

        count--;
        boolean hit =false;
        List<GroupRowExt> list = new LinkedList<>();
        for(int i = 0; i < count; ++i) {

            GroupRowExt row = drop(totalWeight, useGroupRowList, RANDOM);
            list.add(row);

            if(row.getRank() >= ShoprankType.epic.getValue()){
                hit = true;
//                log.info("uid: {} dropTen hit groupId: {} shopId: {} rank: {}", uid, row.getGroupId(), row.getShopId(), row.getRank());
            }
        }

        if(!hit) {

            List<GroupRowExt> useGroupRowHitList = groupExt.getHit10ListByGroupId(groupId);
            int hitTotalWeight = 0;
            for(GroupRowExt groupRow: useGroupRowHitList) {
                hitTotalWeight += groupRow.getWeight();
            }

            GroupRowExt row = drop(hitTotalWeight, useGroupRowHitList, HIT_RANDOM);

            int index = INDEX_RANDOM.nextInt(7);
            list.add(index, row);

//            log.info("uid: {} dropTen extra hit groupId: {} shopId: {} rank: {}", uid, row.getGroupId(), row.getShopId(), row.getRank());

        } else {
            GroupRowExt row = drop(totalWeight, useGroupRowList, RANDOM);
            list.add(row);
        }

        for(GroupRowExt row: list) {
//            log.info("uid: {} dropTen groupId: {} shopId: {} rank: {}", uid, row.getGroupId(), row.getShopId(), row.getRank());
        }

        return list;
    }

    private GroupRowExt drop(int totalWeight, List<GroupRowExt> useGroupRowList, Random random) {

        GroupRowExt row = null;
        int weight = 0;
        int rand = random.nextInt(totalWeight);
        for(GroupRowExt groupRow: useGroupRowList) {

            weight+= groupRow.getWeight();
            if(weight > rand) {
                row = groupRow;
                break;
            }
        }

        return row;
    }


}
